package es.duma.search.universal;

import es.duma.search.Repository;
import es.duma.search.RepositoryManager;
import es.duma.search.SearchRESTService;
import es.duma.util.config.Configurator;
import es.duma.util.log.Log;

import es.duma.util.xmlparse.search.DumaSearch;

import es.duma.util.xsl.TransformXSL;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import java.io.InputStreamReader;
import java.io.OutputStream;

import java.net.HttpURLConnection;

import java.net.MalformedURLException;
import java.net.URL;

import java.rmi.RemoteException;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.RemoveException;

/**
 * Bean del EJB de entidad que implementa el modulo de acceso universal a repositorios.
 * Realiza la peticion REST (http get) a la direccion de busqueda dependiendo de la
 * implementacion cargada. Se aprobecha la persistencia controlada por el bean (BMP) para cargar una de las
 * clases que implementan el acceso especifico a un repositorio.
 */
public class MultimediaRepositoryBean implements EntityBean {
    
    /**
     * Identificador del enty bean y a su vez nombre de la clase que implementa el modulo de acceso al
     * repositorio concreto
     */
    private String idRepository;
    
    /**
     * Clase que implementa el acceso al repositorio concreto. SearchRESTService es una interface Java que deben
     * implementar todas las clases de modulo de acceso a repositorio concreto.
     */
    private SearchRESTService searchRESTservice;
    
    /**
     * Contexto de los EJBs
     */
    private EntityContext _context;

    /**
     * Metodo EJB create 
     * @return
     * @throws CreateException
     */
    public String ejbCreate() throws CreateException {
        Log.debug(this,"Se crea el EntyBean "+idRepository);
        if (idRepository==null){
            throw new CreateException("El Objeto retornado es nulo");
        }
        return idRepository;
    }
    
    /**
     * 
     */
    public void ejbPostCreate() {
        Log.debug(this,"Post-create");
    }

    /**
     * Metodo usado para activar un enty bean, pasando por parametro el identificador
     * @param primaryKey identificador del enty bean
     * @return
     */
    public String ejbFindByPrimaryKey(String primaryKey) {
        Log.debug(this,"Se busca el ejb de entidad por primaryKey: "+primaryKey);
        return primaryKey;
    }
    
    /**
     *
     * @param context
     * @throws EJBException
     */
    public void setEntityContext(EntityContext context) throws EJBException {
        _context = context;
    }
    
    /**
     *
     * @throws EJBException
     */
    public void unsetEntityContext() throws EJBException {
        _context = null;
    }
    
    /**
     *
     * @throws EJBException
     * @throws RemoveException
     */
    public void ejbRemove() throws EJBException, RemoveException {
    }
    
    /**
     *
     * @throws EJBException
     */
    public void ejbActivate() throws EJBException {
        idRepository = (String)_context.getPrimaryKey();
        Log.debug(this,"Se activa el EJB para id:"+idRepository);
    }
    
    /**
     *
     * @throws EJBException
     */
    public void ejbPassivate() throws EJBException {
        Log.debug(this,"El EJB pasa a estado pasivo");
    }
    
    
    /**
     * Metodo ejbLoad del enty bean
     * Se carga la clase de implementacion concreta para acceder al repositorio con identificador el id del enty bean
     * La clase que implementa el acceso al repositorio tiene el mismo nombre que el id del enty bean y esta disponible en
     * el classpath del sistema
     * @throws EJBException
     */
    public void ejbLoad() throws EJBException {
        Log.debug(this,"Load del ejb...");
        // Se carga el searchRESTService segun el idRepository
        try {
            SearchRESTService service=(SearchRESTService)Class.forName(idRepository).newInstance();
            searchRESTservice = service;
            Log.debug(this,"Se ha cargado la implementacion para el repositorio "+idRepository);
  
        } catch (ClassNotFoundException e) {
            Log.error(this,e.getLocalizedMessage());
            searchRESTservice=null;
        } catch (IllegalAccessException e) {
            Log.error(this,e.getLocalizedMessage());
            searchRESTservice=null;
        } catch (InstantiationException e) {
            Log.error(this,e.getLocalizedMessage());
            searchRESTservice=null;
        }
    }
    
    /**
     *
     * @throws EJBException
     */
    public void ejbStore() throws EJBException {
        Log.debug(this,"Store del ejb");
        
    }

    
    /**
     * Metodo de busqueda sobre un repositorio concreto. (segun la implementacion cargada)
     * Se genera la direccion REST a partir del objeto searchOBJ (que contiene la busqueda del susuario encapasulada) y el
     * metodo getREST_URL() de la implemtacion concreta del plugin de acceso
     * @param searchOBJ
     * @return
     */
    public String search(DumaSearch searchOBJ) {
        Log.debug(this,"Llamada al metodo search del entyBean");
        
        // Si no se ha podido cargar la clase de implementación del modulo se devuelve resultado vacio
        if (searchRESTservice==null){
            Log.warn(this,"No se ha podido cargar la clase de implementacion para el modulo "+idRepository+" Se omite la busqueda en este repositorio");
            return "";
        }
        
        
        // Mediante RepositoryManager se obtiene el bean Repository actual
        Repository rep=RepositoryManager.getRepositoryById(idRepository);

        // Se fija el numero maximo de resultados en la busqueda
        Log.debug(this,"Se fija el maximo de resultados de la busqueda "+rep.getMaxResults());
        searchRESTservice.setMaxResults(rep.getMaxResults());


        
        //Obtener la direccion de busqueda REST
        String urlREST="";
        urlREST=searchRESTservice.getREST_URL(searchOBJ);
        Log.debug(this,"Direccion REST de busqueda: "+urlREST);
        

        //Se lanza la  busqueda a la direccion REST obtenida en el paso anterior
        Long ini=System.currentTimeMillis();
        InputStream in=null;
        OutputStream out=new ByteArrayOutputStream();
        HttpURLConnection connection=null;
        URL url;

        try {
            url = new URL(urlREST);
            connection = (HttpURLConnection)url.openConnection();
            Log.debug(this,"Conexion Http establecida");
        }catch (MalformedURLException e) {
            Log.error(this,"Error al formar la URL "+e);
        }catch (IOException e) {
            Log.error(this,"No se puede conectar");
        }

        try {
            in = connection.getInputStream();
            Log.debug(this,"Obteniendo el InputStream de respuesta a la busqueda");
            //Mostramos salida del formato propietario para debug
            //Pasar el InputStream a String
//            InputStream in2=in;
//            BufferedReader br = new BufferedReader(new InputStreamReader(in2));
//            StringBuilder result = new StringBuilder();
//            String line = null;
//            while ((line = br.readLine()) != null) {
//               result.append(line + "\n");
//            }
//            //br.close();
//            Log.debug(this,"Formato propietario:\n"+result.toString());

        } catch (IOException e) {
            Log.error(this,"Error en el buffer "+e);
        }

        // Se obtiene el path del xsl
        String xslPath=Configurator.getPropertieValue("BASE_XSL_MPEG7")+rep.getXsl();
        Log.debug(this,"Se  fija el path del xsl: "+xslPath);
        searchRESTservice.setXslPath(xslPath);
        
        //Realizar transformacion del formato de metadatos propietario al universal
        TransformXSL xsl_transformer=new TransformXSL(xslPath);
        try {
            Log.debug(this,"Se inicia la transformacion xsl al formato universal");
            xsl_transformer.print(in,out);
        } catch (IOException e) {
            Log.error(this,"Error en la transformacion "+e);
        }

        Log.debug(this,"Se realiza la desconexion http");
        connection.disconnect();
        Long fin=System.currentTimeMillis();
        Log.debug(this,"[TIME] conexion HTTP y transformacion XSL:-> "+urlREST+" "+(fin-ini)+ "ms");

        String resultado= out.toString();
        //Log.debug(this,"resultado transformacion "+resultado);
        if (resultado.equalsIgnoreCase(""))
            resultado="<error/>";
        
        return resultado;
    }
}
